package com.renwen.sms.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.renwen.sms.dao.*;
import com.renwen.sms.dto.CourseDto;
import com.renwen.sms.dto.StudentDto;
import com.renwen.sms.dto.PageResult;
import com.renwen.sms.dto.XuanKeDto;
import com.renwen.sms.entity.*;
import com.renwen.sms.entity.Class;
import com.renwen.sms.exception.MyRuntimeException;
import com.renwen.sms.service.StudentService;
import com.renwen.sms.util.Result;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * 学生业务接口实现类
 *
 * @author zuo
 */
@Service
@Transactional
public class StudentServiceImpl implements StudentService {
    @Resource
    private StudentDao studentDao;
    @Resource
    private CourseDao courseDao;
    @Resource
    private TeacherDao teacherDao;
    @Resource
    private XuanKeDao xuanKeDao;
    @Resource
    private ClassDao classDao;
    @Resource
    private PingJiaDao pingJiaDao;

    /**
     * 添加学生
     *
     * @param student 学生对象
     */
    @Override
    public void save(Student student) {
        // 0. 验证学号
        if (!ReUtil.isMatch("^2[0,1]\\d{10,15}$", student.getSNo())) {
            throw new MyRuntimeException("学号格式不对！");
        }
        // 1.验证班级号
        if (!ReUtil.isMatch("^\\d{6,8}$", student.getClsNo())) {
            throw new MyRuntimeException("班级号格式不对！");
        } else {
            QueryWrapper<Class> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("cls_no", student.getClsNo());
            Class aClass = classDao.selectOne(queryWrapper);
            if (aClass == null) {
                throw new MyRuntimeException("输入的班级号不存在！");
            }
        }
        // 2. 验证密码
        if (!ReUtil.isMatch("^\\d{5,15}$", student.getSPwd())) {
            throw new MyRuntimeException("密码格式不对！");
        }
        // 3. 验证姓名
        if (StrUtil.hasBlank(student.getSName())) {
            throw new MyRuntimeException("姓名不能为空！");
        }
        // 4. 验证性别
        if (StrUtil.hasBlank(student.getSSex())) {
            throw new MyRuntimeException("性别不能为空！");
        }
        // 5. 入学时间
        if (!ReUtil.isMatch("^20\\d{2}$", student.getGraduationYear())) {
            throw new MyRuntimeException("入学时间格式不对！,为4位数年份");
        }
        // 6. 执行添加操作
        try {
            //设置默认昵称
            student.setNickName("Jerry");
            studentDao.insert(student);
        } catch (Exception e) {
            throw new MyRuntimeException("添加学生出错！" + e.getMessage());
        }
    }

    /**
     * 修改学生信息
     *
     * @param student 对象
     */
    @Override
    public void update(Student student) {
        // 0. 验证学号
        if (!ReUtil.isMatch("^2[0,1]\\d{10,15}$", student.getSNo())) {
            throw new MyRuntimeException("学号格式不对！");
        }
        // 1. 验证姓名
        if (StrUtil.hasBlank(student.getSName())) {
            throw new MyRuntimeException("姓名不能为空！");
        }
        // 2. 验证性别
        if (StrUtil.hasBlank(student.getSSex())) {
            throw new MyRuntimeException("性别不能为空！");
        }
        // 3. 入学时间
        if (!ReUtil.isMatch("^20\\d{2}$", student.getGraduationYear())) {
            throw new MyRuntimeException("入学时间格式不对！,为4位数年份");
        }
        //4.验证密码
        // 4. 执行修改操作
        try {
            studentDao.updateById(student);
        } catch (Exception e) {
            throw new MyRuntimeException("修改学生信息出错！" + e.getMessage());
        }
    }

    /**
     * 根据学生学号删除
     */
    @Override
    public void delete(String sNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("s_no", sNo);
        try {
            studentDao.deleteByMap(map);
        } catch (Exception e) {
            throw new MyRuntimeException("删除客户时出错！" + e.getMessage());
        }
    }

    /**
     * 批量删除学生信息
     *
     * @param ids 学生编号列表
     */
    @Override
    public void batchDelete(String ids) {
        //字符串切割
        String[] strs = ids.split(",");
        List<Integer> ids1 = new ArrayList<>();
        for (String str : strs) {
            ids1.add(Integer.valueOf(str));
        }
        if (ObjectUtil.hasEmpty(ids1)) {
            throw new MyRuntimeException("请先选择要删除的学生！");
        }
        try {
            studentDao.deleteBatchIds(ids1);
        } catch (Exception e) {
            throw new MyRuntimeException("批量删除失败！" + e.getMessage());
        }
    }

    /**
     * 分页查询所有学生列表
     *
     * @param page      页码
     * @param size      每页显示条数
     * @param searchMap 搜索条件
     * @return 所有学生列表
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public PageResult<StudentDto> list(Integer page, Integer size, Map<String, Object> searchMap) {
        // 构建查询条件
        //搜索框模糊查询
        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        if (!ObjectUtil.hasEmpty(searchMap)) {
            if (!ObjectUtil.hasEmpty(searchMap.get("sex"))) {
                queryWrapper.eq("s_sex", searchMap.get("sex"));
            }
            if (!ObjectUtil.hasEmpty(searchMap.get("name"))) {
                queryWrapper.like("s_name", searchMap.get("name"));
            }
        }
        queryWrapper.select("s_no", "s_name", "s_sex", "id", "s_age", "cls_no", "graduation_year", "s_pwd", "deng_ji");

        // 根据编号降序排序
        queryWrapper.orderByDesc("s_no");

        Page<Student> students = studentDao.selectPage(new Page<Student>(page, size), queryWrapper);
        List<StudentDto> cds = new ArrayList<>();
        for (Student student : students.getRecords()) {
            //根据该学生班级号查询班级名称
            QueryWrapper<Class> classQueryWrapper = new QueryWrapper<>();
            classQueryWrapper.eq("cls_no", student.getClsNo());
            Class aClass = classDao.selectOne(classQueryWrapper);
            //根据该学生班级号查询班主任
            QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
            teacherQueryWrapper.eq("cls_no", student.getClsNo());
            Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);
            //拷贝
            StudentDto studentDto = new StudentDto();
            BeanUtils.copyProperties(student, studentDto);
            if (aClass != null) {
                studentDto.setClsName(aClass.getClsName());
                studentDto.setMajor(aClass.getMajor());
            } else {
                studentDto.setClsName("暂无班级");
            }
            if (teacher != null) {
                studentDto.setClsTeacherName(teacher.getTName());
            } else {
                studentDto.setClsTeacherName("暂无班主任");
            }
            classQueryWrapper.clear();
            teacherQueryWrapper.clear();
            cds.add(studentDto);
        }
        return new PageResult<StudentDto>(cds, students.getTotal());
    }

    /**
     * 根据学生学号查询学生信息
     *
     * @param id 学生学号
     * @return 学生信息
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public Result get(Integer id) {
        if (!NumberUtil.isNumber(String.valueOf(id))) {
            throw new MyRuntimeException("编号应该是数字！");
        }
        try {
            Student student = studentDao.selectById(id);
            StudentDto cd = new StudentDto();
            BeanUtils.copyProperties(student, cd);
            return new Result("查询成功", cd);
        } catch (Exception e) {
            throw new MyRuntimeException("根据学生编号查询出错！" + e.getMessage());
        }
    }

    /**
     * 学生查询自己能选择的所有课程信息
     *
     * @param page      页码
     * @param size      每页显示条数
     * @param searchMap 搜索条件
     * @return 课程表信息
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public PageResult<CourseDto> courseList(Integer page, Integer size, Map<String, Object> searchMap) {
        QueryWrapper<Course> courseQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
        QueryWrapper<XuanKe> xuanKeQueryWrapper = new QueryWrapper<>();
        // 构建查询条件
        //搜索框模糊查询
        if (!ObjectUtil.hasEmpty(searchMap)) {
            //根据课程名称
            if (!ObjectUtil.hasEmpty(searchMap.get("name"))) {
                courseQueryWrapper.like("c_name", searchMap.get("name"));
            }
            //根据课程类型查询课程
            if (!ObjectUtil.hasEmpty(searchMap.get("type"))) {
                courseQueryWrapper.eq("type", searchMap.get("type"));
            }
            //根据学生等级查询课程
            if (!ObjectUtil.hasEmpty(searchMap.get("dengJi"))) {
                courseQueryWrapper.eq("deng_ji", searchMap.get("dengJi"));
            }
        }
        //查询课程表字段
        courseQueryWrapper.select("c_no", "c_name", "kind", "id", "type", "deng_ji");
        // 根据id降序排序
        courseQueryWrapper.orderByDesc("id");
        Page<Course> courses = courseDao.selectPage(new Page<Course>(page, size), courseQueryWrapper);
        List<CourseDto> cds = new ArrayList<>();
        CourseDto courseDto = new CourseDto();
        //遍历课程信息
        for (Course course : courses.getRecords()) {
            //根据课程号查询授课教师(教师表)信息
            teacherQueryWrapper.eq("c_no", course.getCNo());
            Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);
            //添加课程号条件
            if (!ObjectUtil.hasEmpty(searchMap)) {
                //查询选课表里是否有当前学生和课程信息
                //根据学生学号查询选课表信息
                if (!ObjectUtil.hasEmpty(searchMap.get("sNo"))) {
                    xuanKeQueryWrapper.eq("s_no", searchMap.get("sNo"));
                }

            }
            xuanKeQueryWrapper.eq("c_no", course.getCNo());
            XuanKe yiXuanKe = xuanKeDao.selectOne(xuanKeQueryWrapper);

            //存放课程信息对
            //拷贝属性
            BeanUtils.copyProperties(course, courseDto);
            //判断当前是否安排了授课教师
            if (teacher != null) {
                courseDto.setTeacher(teacher.getTName());
            } else {
                courseDto.setTeacher("暂无");
            }
            //判断是否选课
            if (yiXuanKe != null) {
                //判断是否已有成绩，已有成绩代表已经结课
                if (yiXuanKe.getCGrade() == null) {
                    courseDto.setState(1);
                    //添加教师信息到数组
                    cds.add(courseDto);
                } else {
                    if (yiXuanKe.getCGrade().trim().length() == 0) {
                        courseDto.setState(1);
                        //添加教师信息到数组
                        cds.add(courseDto);
                    }
                }
            } else {
                courseDto.setState(0);
                //添加教师信息到数组
                cds.add(courseDto);
            }
            //清空查询条件
            teacherQueryWrapper.clear();
            xuanKeQueryWrapper.clear();
            //重新开辟内存地址
            courseDto = new CourseDto();
        }
        return new PageResult<CourseDto>(cds, courses.getTotal());
    }


    /**
     * 学生查询所有成绩信息
     *
     * @param page      页码
     * @param size      每页显示条数
     * @param searchMap 搜索条件
     * @return 成绩信息
     */
    @Override
    public PageResult<XuanKeDto> studentGradesList(Integer page, Integer size, Map<String, Object> searchMap) {
        QueryWrapper<XuanKe> xuanKeQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Course> courseQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
        // 构建查询条件
        if (!ObjectUtil.hasEmpty(searchMap)) {
            if (!ObjectUtil.hasEmpty(searchMap.get("sNo"))) {
                xuanKeQueryWrapper.eq("s_no", searchMap.get("sNo"));
            }
        }
        //查询选课表字段
        xuanKeQueryWrapper.select("c_no", "s_no", "c_grade", "id", "t_no");
        // 根据id降序排序
        xuanKeQueryWrapper.orderByDesc("c_no");
        Page<XuanKe> xuanKes = xuanKeDao.selectPage(new Page<XuanKe>(page, size), xuanKeQueryWrapper);
        List<XuanKeDto> cds = new ArrayList<>();
        XuanKeDto xuanKeDto = new XuanKeDto();
        //遍历当前学生的选课信息
        for (XuanKe xuanKe : xuanKes.getRecords()) {
            courseQueryWrapper.eq("c_no", xuanKe.getCNo());
            teacherQueryWrapper.eq("t_no", xuanKe.getTNo());
            Course course = courseDao.selectOne(courseQueryWrapper);
            Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);
            //拷贝属性
            BeanUtils.copyProperties(xuanKe, xuanKeDto);
            //判断成绩是否通过
            //判断该课程学生是否有成绩
            if (xuanKe.getCGrade() != null) {
                if (xuanKe.getCGrade().trim().length() != 0) {
                    if (Integer.valueOf(xuanKe.getCGrade()) < 60) {
                        xuanKeDto.setPass("成绩未合格");
                    } else {
                        xuanKeDto.setPass("成绩合格");
                    }
                } else {
                    xuanKeDto.setCGrade("还未有成绩");
                }
            } else {
                xuanKeDto.setCGrade("还未有成绩");
            }
            //判断课程对象是否为空
            if (course != null) {
                xuanKeDto.setCName(course.getCName());
            }
            //判断教师对象是否为空
            if (teacher != null) {
                xuanKeDto.setTName(teacher.getTName());
            }
            //清空查询条件
            courseQueryWrapper.clear();
            teacherQueryWrapper.clear();
            // 构建查询条件
            if (!ObjectUtil.hasEmpty(searchMap.get("type"))) {
                //成绩是否合格
                if (searchMap.get("type").toString().equals(xuanKeDto.getCGrade())) {
                    //添加教师信息到数组
                    cds.add(xuanKeDto);
                } else if (searchMap.get("type").toString().equals(xuanKeDto.getPass())) {
                    //添加教师信息到数组
                    cds.add(xuanKeDto);
                }
            } else {
                //添加教师信息到数组
                cds.add(xuanKeDto);
            }
            //重新开辟内存地址
            xuanKeDto = new XuanKeDto();
        }
        return new PageResult<XuanKeDto>(cds, xuanKes.getTotal());
    }

    /**
     * 学生查询已完结课程信息
     * :根据教师号查询选课信息
     *
     * @param page      页码
     * @param size      每页显示条数
     * @param searchMap 搜索条件
     * @return 已完结课程信息
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public PageResult<XuanKeDto> studentJieKeList(Integer page, Integer size, Map<String, Object> searchMap) {
        QueryWrapper<XuanKe> xuanKeQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Student> studentQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Course> courseQueryWrapper = new QueryWrapper<>();
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
        // 构建查询条件
        if (!ObjectUtil.hasEmpty(searchMap)) {
            if (!ObjectUtil.hasEmpty(searchMap.get("sNo"))) {
                xuanKeQueryWrapper.eq("s_no", searchMap.get("sNo"));
            }
        }
        //查询选课表字段
        xuanKeQueryWrapper.select("c_no", "s_no", "c_grade", "id", "t_no");
        // 根据id降序排序
        xuanKeQueryWrapper.orderByDesc("id");
        Page<XuanKe> xuanKes = xuanKeDao.selectPage(new Page<XuanKe>(page, size), xuanKeQueryWrapper);
        List<XuanKeDto> cds = new ArrayList<>();
        XuanKeDto xuanKeDto = new XuanKeDto();
        //遍历当前学生的选课信息
        for (XuanKe xuanKe : xuanKes.getRecords()) {
            //判断该课程学生是否有成绩
            if (xuanKe.getCGrade() != null) {
                //判断成绩是否为空字符串
                if (xuanKe.getCGrade().trim().length() != 0) {
                    studentQueryWrapper.eq("s_no", xuanKe.getSNo());
                    courseQueryWrapper.eq("c_no", xuanKe.getCNo());
                    teacherQueryWrapper.eq("t_no", xuanKe.getTNo());
                    Student student = studentDao.selectOne(studentQueryWrapper);
                    Course course = courseDao.selectOne(courseQueryWrapper);
                    Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);
                    //拷贝属性
                    BeanUtils.copyProperties(xuanKe, xuanKeDto);
                    //判断学生对象是否为空
                    if (student != null) {
                        xuanKeDto.setSName(student.getSName());
                    }
                    //判断课程对象是否为空
                    if (course != null) {
                        xuanKeDto.setCName(course.getCName());
                    }
                    //判断教师对象是否为空
                    if (teacher != null) {
                        xuanKeDto.setTName(teacher.getTName());
                    }
                    //清空查询条件
                    courseQueryWrapper.clear();
                    studentQueryWrapper.clear();
                    teacherQueryWrapper.clear();
                    //添加教师信息到数组
                    cds.add(xuanKeDto);
                    //重新开辟内存地址
                    xuanKeDto = new XuanKeDto();
                }

            }
        }
        return new PageResult<XuanKeDto>(cds, xuanKes.getTotal());
    }

    /**
     * 导出学生表信息到桌面
     */
    @Override
    public void outStudent() {

        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("s_no", "s_name", "s_sex", "s_age", "deng_ji", "cls_no", "graduation_year");
        // 根据编号降序排序
        queryWrapper.orderByDesc("s_no");
        List<Student> students = studentDao.selectList(queryWrapper);
        //创建工作簿 类似于创建Excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建 sheetname页名
        XSSFSheet sheet = workbook.createSheet("学生信息");
        sheet.setColumnWidth(3, 20 * 256);//给第3列设置为20个字的宽度
        sheet.setColumnWidth(4, 20 * 256);//给第4列设置为20个字的宽度
        //创建一行,下标从0开始
        XSSFRow row = sheet.createRow(0);
        //创建这行中的列,下标从0开始 （表头）
        XSSFCell cell = row.createCell(0);
        // 给cell 0下表赋值
        cell.setCellValue("学号");
        //创建这行中的列,并给该列直接赋值
        row.createCell(1).setCellValue("姓名");
        row.createCell(2).setCellValue("性别");
        row.createCell(3).setCellValue("年龄");
        row.createCell(4).setCellValue("专业");
        row.createCell(5).setCellValue("班级");
        row.createCell(6).setCellValue("班主任");
        row.createCell(7).setCellValue("年级");
        row.createCell(8).setCellValue("入学时间");
        int i = 0;
        for (Student student : students) {
            QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
            teacherQueryWrapper.eq("cls_no", student.getClsNo());
            Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);

            QueryWrapper<Class> classQueryWrapper = new QueryWrapper<>();
            classQueryWrapper.eq("cls_no", student.getClsNo());
            Class aClass = classDao.selectOne(classQueryWrapper);
            // 设置表里内容
            row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(student.getSNo());
            row.createCell(1).setCellValue(student.getSName());
            row.createCell(2).setCellValue(student.getSSex());
            row.createCell(3).setCellValue(student.getSAge());
            if (aClass != null) {
                row.createCell(4).setCellValue(aClass.getMajor());
                row.createCell(5).setCellValue(aClass.getClsName());
            }
            if (teacher != null) {
                row.createCell(6).setCellValue(teacher.getTName());
            }
            row.createCell(7).setCellValue(student.getDengJi());
            row.createCell(8).setCellValue(student.getGraduationYear());
            i++;

            classQueryWrapper.clear();
            teacherQueryWrapper.clear();
        }
        File file = new File("C:\\Users\\zuo\\Desktop\\学生信息表.xlsx");
        FileOutputStream stream = null;
        try {
            stream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 需要抛异常
        try {
            workbook.write(stream);
            //关流
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 学生网上选课
     */
    @Override
    public void studentXuanKe(String sNo, String cNo) {
        XuanKe xuanKe = new XuanKe();
        QueryWrapper<Teacher> teacherQueryWrapper = new QueryWrapper<>();
        teacherQueryWrapper.eq("c_no", cNo);
        Teacher teacher = teacherDao.selectOne(teacherQueryWrapper);
        if (teacher != null) {
            xuanKe.setTNo(teacher.getTNo());
        }
        xuanKe.setCNo(cNo);
        xuanKe.setSNo(sNo);
        xuanKeDao.insert(xuanKe);
    }

    /**
     * 学生取消选课
     */
    @Override
    public void delXuanKe(String cNo,String sNo){
        try {
            QueryWrapper<XuanKe> xuanKeQueryWrapper = new QueryWrapper<>();
            xuanKeQueryWrapper.eq("c_no",cNo);
            xuanKeQueryWrapper.eq("s_no",sNo);
            xuanKeDao.delete(xuanKeQueryWrapper);
        } catch (Exception e) {
            throw new MyRuntimeException("取消选课时出错！" + e.getMessage());
        }
    }

    /**
     * 课程评价
     * @param pingJia
     */
    @Override
    public void pingJia(PingJia pingJia) {
        try {
            QueryWrapper<PingJia> pingJiaQueryWrapper = new QueryWrapper<>();
            pingJiaQueryWrapper.eq("s_no", pingJia.getSNo());
            pingJiaQueryWrapper.eq("c_no", pingJia.getCNo());
            PingJia pingJia1 = pingJiaDao.selectOne(pingJiaQueryWrapper);
            if (pingJia1 != null) {
                throw new MyRuntimeException("不可重复评价！！！");
            }else {
                pingJiaDao.insert(pingJia);
            }
        }catch (Exception e){
            throw new MyRuntimeException(e.getMessage());
        }
    }
}
